/**
 * Auteur : Dominique GUERIN
 * dominiquephDOTguerinATgmailDOT..
 * dominiqueDOTguerinATinseeDOTfr(ance)  
 * Remerciements: � Keith Brown pour ses deux livres sur la s�curit� sous Windows et ses diff�rents articles
 *                 et � Michel Barnett de Microsoft pour ses deux articles 
 *                ".NET Remoting Authentication and Authorization Sample"  et le code qui les accompagne
 *  Le code est utilisable, modifiable et redistribuable � volont� sous la condition de ne pas supprimer ces 7 lignes.
 */ 
 
 package fr.doume.jna.sspi;

//tomcat 5.5
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

//tomcat 6
//import org.apache.juli.logging.Log;
//import org.apache.juli.logging.LogFactory;
import java.util.Date;

import fr.doume.jna.authenticator.Parameters;
import fr.doume.jna.authenticator.AuthenticationContext;
import fr.doume.jna.sspi.SSPException;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.W32Errors;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

import fr.doume.jna.jna.Advapi32bis;

public class TranslationRolesIntoSids
{
	private static Log log = LogFactory.getLog(TranslationRolesIntoSids.class);


   /**
   * Nombre de sids
   */
  private int sidsCount;
  
	private String[] groups;

	private Date creationDate;

  /**
  * utilis�e comme garde pour la coh�rence de l'instance de la classe
  */
	private boolean translated;
  private byte[][] sids_array = null;

  private Parameters parameters;
  
  private AuthenticationContext authenticationContext;

	public TranslationRolesIntoSids( AuthenticationContext ac)
	{		
		parameters = ac.getParameters();
		authenticationContext = ac;
		sidsCount = 0;
		groups= new String[0];
		creationDate = new Date();
		translated = false;
	}

  /**
  *  Cette m�thode appelle <code>translateToSids</code> si la traduction n'a pas �t� encore r�alis�e, 
  * puis v�rifie la coh�rence des octets re�us par l'appel de <code>verifySids</code>.
  * Si tout est correct, cette m�thode positionne ensuite � vrai <code>traductionRealisee</code>.
  * NegoServer renvoie un tableau de SIDs, chaque SID �tant conserv� sous forme de tableau d'octets.
  * Ce tableau n'a de signification que lors des appels � l'API Windows.
  */
	public int getSidsCount(String[] roles)
	throws SSPException
	{
    if(!translated) 
    {
      if (! translateToSids( roles) )
      {
        throw new SSPException("Translation from roles to sids failed");
      }
      groups = roles;
      translated = true;
    }//if(!traductionRealisee)
    sidsCount = sids_array.length;
		return sidsCount;
	}
	
	public String[] getGroups()
	{
    return groups;
  }
  
	public int getSidsCount()
	throws SSPException
	{
		if (sidsCount == 0 ){
      if( !translated)
			throw new SSPException("Count of roles is zero");
		}
		return sidsCount;
	}
	/**
	* Retourne un tableau d'octets repr�sentant les Sids
	*/
	public byte[][] getSids()
	throws SSPException
	{
		if (sidsCount == 0 ){
      if( !translated)
			throw new SSPException("Count of roles is zero");
		}
		return sids_array;//return sids;
	}

	/**
	* Renvoi de la date de cr�ation de l'instance. Permet de g�rer un cache de traduction d'une dur�ee limit�e
	*/
	public Date getDate()
	{
    return creationDate;
	}

  private boolean translateToSids( String[] roles)
  //throws SSPException
  {
    sids_array = new byte[roles.length][];
    for (int i = 0; i < roles.length; i++)
    {
      try
      {
        sids_array[i] = getSidByName( roles[i] );
      }
      catch(Win32Exception e)
      {
        sids_array[i] = null;
      }
    }
     return true;
  }
  public AuthenticationContext getAuthenticationContext()
  {
    return authenticationContext;
  }


  private byte[] getSidByName( String accountName) 
	{
		IntByReference lengthSid = new IntByReference(0);
		IntByReference cchDomainName = new IntByReference(0);
		IntByReference peUse = new IntByReference(0);
		
		if (Advapi32bis.INSTANCE.LookupAccountName(null, accountName, null, lengthSid, null, cchDomainName, peUse))
		{
			throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
		}
		
		int rc = Kernel32.INSTANCE.GetLastError();
		if (lengthSid.getValue() == 0 || rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) 
		{
			throw new Win32Exception(rc);
		}

		byte[] nativesid = new byte[lengthSid.getValue()];
		char[] referencedDomainName = new char[cchDomainName.getValue() + 1]; 

		if (! Advapi32bis.INSTANCE.LookupAccountName(null, accountName,nativesid, lengthSid, referencedDomainName, cchDomainName, peUse))
		{
			throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
		}
		if (log.isDebugEnabled()) log.debug("peUse : " + peUse.getValue());
    return nativesid;
	}



}

